package com.kl;

import com.kl.constant.KeyParams;
import com.kl.constant.TankModel;
import com.kl.constant.Windows;
import com.kl.enums.*;
import com.kl.model.base.AbstractAttack;
import com.kl.model.pojo.*;
import com.kl.utils.CollectionUtils;
import com.kl.utils.ContextUtil;
import lombok.Getter;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.Closeable;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.LockSupport;

import static com.kl.constant.AttackModel.DEFAULT_SIZE;
import static com.kl.constant.TankModel.EXPLODE_SIZE_ALL;

/**
 * @author CC
 * time 2024-05-25
 * description
 */
public class TankGame extends JPanel implements Runnable , Closeable {
    /**
     * 玩家集合
     */
    @Getter
    private volatile static ArrayList<HeroTank> players = new ArrayList<HeroTank>();
    ;
    /**
     * 敌人集合
     */
    @Getter
    private volatile static ArrayList<EnemyTank> enemies = new ArrayList<>();

    private static volatile GameState gameState = GameState.EMPTY;
    @Getter
    private JFrame jFrame;

    private final GameType gameType;

    public static boolean isEnd() {
        return gameState == GameState.END;
    }

    public static void runGame() {
        TankGame.gameState = GameState.RUNNING;
    }

    public TankGame(JFrame jFrame) {
        super();
        this.jFrame = jFrame;
        this.gameType = GameType.SINGLE;
        this.init();
    }

    public TankGame(final JFrame jFrame, final ArrayList<HeroTank> players, final ArrayList<EnemyTank> enemies, final GameType gameType) {
        super();
        this.jFrame = jFrame;
        this.gameType = gameType;
        TankGame.players = players;
        TankGame.enemies = enemies;
        this.init();
    }

    @Override
    public void run() {
        while (true) {
            //延迟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            this.repaint();
            if (TankGame.checkWinner()) {
                gameState = GameState.END;
                break;
            }
        }
        LockSupport.unpark((Thread) ContextUtil.getCache(KeyParams.LOCK));
    }


    public static boolean checkWinner() {
        if (CollectionUtils.isEmpty(enemies)) {
            JOptionPane.showMessageDialog(null, Windows.WINNER_INFO, "提示", JOptionPane.INFORMATION_MESSAGE);
            return true;
        } else if (CollectionUtils.isEmpty(players)) {
            JOptionPane.showMessageDialog(null, Windows.LOSER_INFO, "提示", JOptionPane.WARNING_MESSAGE);
            return true;
        }
        return false;
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        switch (gameState) {
            case RUNNING:
                break;
            case INIT:
                return;
            case PAUSE:
                return;
            case END:
                return;
        }
        //绘制玩家坦克
        g.setColor(TankType.HERO.getColor());
        this.drawList(players, g);
        //绘制敌人坦克
        g.setColor(TankType.ENEMY.getColor());
        this.drawList(enemies, g);
        //绘制爆炸
        for (int i = 0; i < App.getEXPLODES().size(); i++) {
            Explode explode = App.getEXPLODES().get(i);
            if (explode.getLife() > 6) {
                g.drawImage(((BufferedImage) ContextUtil.getCache(KeyParams.EXPLODE_INIT)), explode.getX(), explode.getY(), EXPLODE_SIZE_ALL, EXPLODE_SIZE_ALL, this);
            } else if (explode.getLife() > 3) {
                g.drawImage(((BufferedImage) ContextUtil.getCache(KeyParams.EXPLODE_MID)), explode.getX(), explode.getY(), EXPLODE_SIZE_ALL, EXPLODE_SIZE_ALL, this);
            } else {
                g.drawImage(((BufferedImage) ContextUtil.getCache(KeyParams.EXPLODE_END)), explode.getX(), explode.getY(), EXPLODE_SIZE_ALL, EXPLODE_SIZE_ALL, this);
            }
            explode.lifeDown();
            if (explode.getState() == State.DEATH) {
                App.getEXPLODES().remove(explode);
            }
        }

    }

    /**
     * 加载坦克集合
     */
    private void initParams() {
        //绘制玩家坦克
        HeroTank tank = new HeroTank(100, 300);
        players.add(tank);
        jFrame.addKeyListener((tank));
        //敌人坦克
        for (int i = 0; i < GameSetting.INSTANCE.getEnemyNum(); i++) {
            EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 100);
            enemyTank.setDirect(Direct.random());
            enemies.add(enemyTank);
            App.getPOOL().execute(enemyTank);
        }
    }

    /**
     * 加载游戏
     */
    private void init() {
        gameState = GameState.INIT;
        this.setBackground(Color.GRAY);
        this.initParams();
    }

    /**
     * 绘制坦克
     *
     * @param tank 坦克实例
     * @param g    画笔
     */
    private void drawTank(final Tank tank, Graphics g) {
//        int x = tank.getX();
//        int y = tank.getY();
//        int xCenter = x- BODY_MID_SIZE;
//        int yCenter = y-BODY_MID_SIZE;
//        Direct direct = tank.getDirect();
//        //中心部分
//        g.fill3DRect(xCenter,yCenter, BODY_SIZE,BODY_SIZE,false);
//        g.fillOval(xCenter,yCenter,BODY_SIZE,BODY_SIZE);
//        //管子
//        switch (direct){
//            case UP:
//                //左半部分
//                g.fill3DRect(xCenter-BODY_MID_SIZE,y-BODY_MID_SIZE-WHEEL_WIDTH,WHEEL_WIDTH,WHEEL_HEIGHT,false);
//                //右半部分
//                g.fill3DRect(x+BODY_MID_SIZE,y-BODY_MID_SIZE-BODY_MID_SIZE,WHEEL_WIDTH,WHEEL_HEIGHT,false);
//                g.drawLine(x,y, x, y- PIPED_LENGTH);
//                break;
//            case DOWN:
//                //左半部分
//                g.fill3DRect(xCenter-BODY_MID_SIZE,y-BODY_MID_SIZE-WHEEL_WIDTH,WHEEL_WIDTH,WHEEL_HEIGHT,false);
//                //右半部分
//                g.fill3DRect(x+BODY_MID_SIZE,y-BODY_MID_SIZE-BODY_MID_SIZE,WHEEL_WIDTH,WHEEL_HEIGHT,false);
//                g.drawLine(x, y, x, y+PIPED_LENGTH);
//                break;
//            case LEFT:
//                //上半部分
//                g.fill3DRect(xCenter-WHEEL_WIDTH,yCenter-BODY_MID_SIZE,WHEEL_HEIGHT,WHEEL_WIDTH,false);
//                //下半部分
//                g.fill3DRect(xCenter-WHEEL_WIDTH,yCenter+BODY_MID_SIZE+WHEEL_WIDTH,WHEEL_HEIGHT,WHEEL_WIDTH,false);
//                g.drawLine(x, y, x-PIPED_LENGTH,y);
//                break;
//            case RIGHT:
//                //上半部分
//                g.fill3DRect(xCenter-WHEEL_WIDTH,yCenter-BODY_MID_SIZE,WHEEL_HEIGHT,WHEEL_WIDTH,false);
//                //下半部分
//                g.fill3DRect(xCenter-WHEEL_WIDTH,yCenter+BODY_MID_SIZE+WHEEL_WIDTH,WHEEL_HEIGHT,WHEEL_WIDTH,false);
//                g.drawLine(x, y, x+PIPED_LENGTH,y);
//                break;
//        }
        String name = tank.getOrigin().name();
        int beginX = tank.getX() - TankModel.BODY_HALF_SIZE;
        int beginY = tank.getY() - TankModel.BODY_HALF_SIZE;
        g.drawImage(((BufferedImage) ContextUtil.getCache((name + tank.getDirect().getDesc()).intern())), beginX, beginY, TankModel.BODY_SIZE, TankModel.BODY_SIZE, this);
    }

    /**
     * 绘制子弹
     *
     * @param attack
     * @param g
     */
    private void drawShot(AbstractAttack attack, Graphics g) {
        g.draw3DRect(attack.getX(), attack.getY(), DEFAULT_SIZE, DEFAULT_SIZE, false);
    }

    private void drawList(ArrayList<? extends Tank> tanks, Graphics g) {
        if (!CollectionUtils.isEmpty(tanks)) {
//            synchronized (tanks){
            Iterator<? extends Tank> iterator = tanks.iterator();
            while (iterator.hasNext()) {
                Tank tank = iterator.next();
                if (tank.getStatus() == State.DEATH) {
                    //若死亡则移除
                    iterator.remove();
                    App.getPOOL().execute(tank::destroy);
                    continue;
                }
                this.drawTank(tank, g);
                //绘制子弹
                CopyOnWriteArrayList<AbstractAttack> attacks = tank.getAttacks();
                if (!CollectionUtils.isEmpty(attacks)) {
                    for (int j = 0; j < attacks.size(); j++) {
                        AbstractAttack attack = attacks.get(j);
                        if (attack.getState() == State.ALIVE) {
                            //绘制子弹
//                            CompletableFuture.runAsync(()->{
                            this.drawShot(attack, g);
//                            },App.getPOOL());
                        } else {
                            tank.getAttacks().remove(attack);
                            App.getPOOL().execute(attack::destroy);
                            j--;
                        }
                    }
                }
            }
//            }
        }
    }

    @Override
    public void close() throws IOException {
        if (players != null) {
            players.forEach(tank -> tank.getAttacks().clear());
            players.clear();
        }
        if (enemies != null) {
            enemies.forEach(tank -> {
                tank.destroy();
                App.getPOOL().remove(tank);
            });
            enemies.clear();
            this.jFrame = null;
        }
    }
}
